package com.atwisdom.star.service.specification.impl;

import com.alibaba.fastjson.JSONObject;
import com.atwisdom.star.common.util.JsonUtil;
import com.atwisdom.star.common.util.UuidTool;
import com.atwisdom.star.common.vo.JsonResult;
import com.atwisdom.star.common.vo.ModelType;
import com.atwisdom.star.common.vo.ResultInfo;
import com.atwisdom.star.core.dao.pojo.modelClass.hier.HierInstance;
import com.atwisdom.star.core.dao.pojo.modelClass.logic.LogicInstance;
import com.atwisdom.star.core.dsl.modelClass.hier.Impl.HierInstanceDslServiceImpl;
import com.atwisdom.star.core.dsl.modelClass.logic.Impl.LogicInstanceDslServiceImpl;
import com.atwisdom.star.core.dsl.modelClass.resource.Impl.ResourceInstanceDslServiceImpl;
import com.atwisdom.star.exception.pojo.BusinessException;
import com.atwisdom.star.service.specification.SpecificationService;
import com.atwisdom.star.service.util.LogicUtil;
import com.atwisdom.star.service.util.ResourceUtil;
import com.atwisdom.star.service.util.ValidateUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;


/**
 * @ClassName: SpecificationServiceImpl
 * @ Description:
 * @author: wjj
 * @Date 2024/7/19
 */
@Service
public class SpecificationServiceImpl implements SpecificationService {

    @Autowired
    private LogicUtil logicUtil;

    @Autowired
    private LogicInstanceDslServiceImpl logicInstanceDslServiceImpl;

    @Autowired
    private HierInstanceDslServiceImpl hierInstanceDslServiceImpl;

    @Autowired
    private ResourceInstanceDslServiceImpl resourceInstanceDslServiceImpl;

    @Autowired
    ResourceUtil resourceUtil;

    private final String CLASS_NAME_SPECIFICATION = "Specification";
    private final String CLASS_NAME_LABORATORY = "Laboratory";
    private final String TYPE = "logic";
    private final String specificationModel = "logic";
    private final String laboratoryModel = "logic";
    private final String specificationLinkType = "resource";
    private final String laboratoryLinkType = "resource";
    private final String specificationLinkClassName = "TechnologyParams";
    private final String laboratoryLinkClassName = "LaboratoryParams";
    private final String laboratoryClassName = "Laboratory";
    private final String specificationClassName = "Specification";

    private final String specificationParentId = "1bcdiht1qeow00";
    private final String laboratoryParentId = "o68gn3eba7400";


    /**
     * 根据产品id查询工艺参数组容器存在返回不存在新增-未启用
     */
    @Override
    @Transactional
    public ResultInfo<?> querySpecificationByProductId(JSONObject data) throws BusinessException {
        int id = data.getIntValue("id");
        if (null == data.get("id")) {
            return JsonResult.error(500, "id不能为空");
        }
        JSONObject values = JsonUtil.buildJson(new Object[]{"if_equ", id, "sf_name", data.getString("sf_name"), "sf_code", data.getString("sf_code"), "bf_template", true});
        return JsonResult.success(logicUtil.queryUpdateOrAdd(CLASS_NAME_SPECIFICATION, TYPE, values, "if_equ", "bf_template"));
    }

    /**
     * 1.根据产品id查询产品规格logic容器存在返回不存在新增
     * 2.同步采集点信息到工艺参数
     *
     * @param data
     * @return 品规及其hier
     * @throws BusinessException
     */
    @Override
    @Transactional
    public ResultInfo<?> querySpecificationByProductIdAndSync(JSONObject data) throws BusinessException {
        int id = data.getIntValue("id");
        if (null == data.get("id")) {
            return JsonResult.error(500, "id不能为空");
        }
        Long equipId = data.getLong("equipId"); //设备ID
        if (null == equipId) {
            return JsonResult.error(500, "equipId不能为空");
        }
        JSONObject values = JsonUtil.buildJson(new Object[]{"if_equ", id, "sf_name", data.getString("sf_name"), "sf_code", data.getString("sf_code"), "bf_template", true});
        JSONObject ret = logicUtil.queryUpdateOrAdd(CLASS_NAME_SPECIFICATION, TYPE, values, "if_equ", "bf_template");
        data.put("containerId", ret.getLong("id"));
        return syncToTechnologyParams(data);
    }

    /**
     * 同步采集点到工艺参数
     *
     * @param data
     * @return
     * @throws BusinessException
     */
    @Override
    @Transactional
    public ResultInfo<?> syncToTechnologyParams(JSONObject data) throws BusinessException {
        Long equipId = data.getLong("equipId"); //设备ID
        Long containerId = data.getLong("containerId"); //产品logic容器ID
        String productName = data.getString("sf_name"); //产品名称
        String productCode = data.getString("sf_code"); //产品编号
        String imgNumber = data.getString("imgNumber"); //产品图号
        //查询产品规格容器下的工艺参数
        List<HierInstance> paramHiers = this.hierInstanceDslServiceImpl.queryByContainerId(ModelType.Logic.getCode(), specificationClassName, containerId);
        //过滤掉手动添加的工艺参数
        List<HierInstance> filteredParamHiers = paramHiers.stream()
                .filter(hierInstance -> hierInstance.getLinkId() != null && hierInstance.getValues() != null && hierInstance.getValues().getLong("pointId") != null)
                .collect(Collectors.toList());
        //工艺参数对应的采集点ID集合
        List<Long> paramPointIds = filteredParamHiers.stream().map(hierInstance -> hierInstance.getValues().getLong("pointId")).collect(Collectors.toList());
        //品规下采集点ID与工艺参数ID的映射
        Map<Long, Long> map = filteredParamHiers.stream().collect(Collectors.toMap(hierInstance -> hierInstance.getValues().getLong("pointId"), hierInstance -> hierInstance.getLinkId()));

        //查询产品规格所属设备容器
        String condition = "className=='" + "EquipPoint" + "'&&type=='" + "logic" + "'&&if_equ==" + equipId + "&&bf_template==true";
        List<LogicInstance> list = logicInstanceDslServiceImpl.fetchInstanceList(condition, "EquipPoint", null);

        if (list != null && list.size() > 0) {
            LogicInstance l = list.get(0);
            //获取产品规格相应设备logic容器下的采集点
            List<HierInstance> pointHiers = this.hierInstanceDslServiceImpl.queryByContainerId(ModelType.Logic.getCode(), l.getClassName(), l.getId());
            //过滤掉null
            List<HierInstance> filteredPointHiers = pointHiers.stream().filter(hierInstance -> hierInstance.getLinkId() != null).collect(Collectors.toList());

            decisionSync(paramPointIds, filteredPointHiers, productName, productCode, imgNumber, containerId, map);
            deleteSyncPointAndTechparams(paramPointIds, filteredPointHiers, map);
        }
        return JsonResult.success(logicUtil.queryByIdAndHier(containerId));
    }

    /**
     * 采集点与工艺参数的同步策略
     */
    private void decisionSync(List<Long> paramPointIds, List<HierInstance> filteredPointHiers, String productName, String productCode, String imgNumber, Long containerId, Map<Long, Long> map) {
        for (HierInstance pointHier : filteredPointHiers) {
            Long pointId = pointHier.getLinkId();
            if (pointId != null) {
                //获取采集点最新resource value
                JSONObject jsonObject = resourceInstanceDslServiceImpl.queryById(pointId);
                JSONObject values = jsonObject.getJSONObject("values");
                if (values != null && !paramPointIds.contains(pointId) && "是".equals(values.getString("status"))) {  //新采集点启用则同步
                    String paramName = values.getString("paramName");   //工艺参数名称
                    JSONObject techParamValues = new JSONObject();
                    techParamValues.put("pointId", pointId);
                    techParamValues.put("sf_name", paramName);
                    techParamValues.put("productName", productName);
                    techParamValues.put("productCode", productCode);
                    techParamValues.put("imgNumber", imgNumber);

                    JSONObject addTechnologyParams = new JSONObject();
                    addTechnologyParams.put("type", specificationLinkType);
                    addTechnologyParams.put("className", specificationLinkClassName);
                    addTechnologyParams.put("name", UuidTool.getUUID32());
                    addTechnologyParams.put("values", techParamValues);
                    addTechnologyParams.put("containerId", containerId);
                    //采集点启用，则同步到工艺参数
                    addTechnologyParams(addTechnologyParams);
                } else if (paramPointIds.contains(pointId) && "否".equals(values.getString("status"))) {  //新采集点停用，则从品规容器删除
                    //采集点被停用，则从品规容器删除对应工艺参数
                    resourceInstanceDslServiceImpl.deleteByIds(Arrays.asList(map.get(pointId)));
                }
            }
        }
    }

    /**
     * 如果采集点被删除，相应工艺参数也当被移除
     */
    private void deleteSyncPointAndTechparams(List<Long> paramPointIds, List<HierInstance> filteredPointHiers, Map<Long, Long> map) {
        //设备下采集点集合
        List<Long> pointIds = filteredPointHiers.stream().map(tmp -> tmp.getLinkId()).collect(Collectors.toList());

        List<Long> difference = paramPointIds.stream()
                .filter(element -> !pointIds.contains(element))
                .collect(Collectors.toList());
        for (Long id : difference) {
            resourceInstanceDslServiceImpl.deleteByIds(Arrays.asList(map.get(id)));
        }
    }

    /**
     * 新增工艺参数并关联工艺参数组容器
     *
     * @param data
     * @return 工艺参数
     * @throws BusinessException
     */
    @Override
    @Transactional
    public ResultInfo<?> addTechnologyParams(JSONObject data) throws BusinessException {
        String type = data.getString("type");
        String className = data.getString("className");
        String name = data.getString("name");
        JSONObject values = data.getJSONObject("values");

        String containerId = data.getString("containerId");
        ValidateUtil.hasEmpty(containerId, type, className, name, values);
        // 添加资源实例
        JSONObject addJson = resourceInstanceDslServiceImpl.add(type, className, name, values);
        if (addJson != null && StringUtils.isNotEmpty(addJson.getString("id"))) {
            String linkId = addJson.getString("id");
            JSONObject hierInsJson = JsonUtil.buildJson(new Object[]{"containerModel", this.specificationModel, "containerClassName", this.specificationClassName, "containerId", containerId, "parentId", this.specificationParentId, "linkId", linkId, "linkType", specificationLinkType, "linkClassName", specificationLinkClassName, "values", JsonUtil.get(addJson, "values")});
            hierInstanceDslServiceImpl.addChild(hierInsJson);
        }
        return JsonResult.success(addJson);
    }

    /**
     * 根据产品id查询实验室参数组容器存在返回不存在新增
     *
     * @param data
     * @return 品规及其hier
     * @throws BusinessException
     */
    @Override
    @Transactional
    public ResultInfo<?> queryLaboratoryByProductId(JSONObject data) throws BusinessException {
        int id = data.getIntValue("id");
        if (null == data.get("id")) {
            return JsonResult.error(500, "id不能为空");
        }
        JSONObject values = JsonUtil.buildJson(new Object[]{"if_equ", id, "sf_name", data.getString("sf_name"), "sf_code", data.getString("sf_code"), "bf_template", true});
        return JsonResult.success(logicUtil.queryUpdateOrAdd(CLASS_NAME_LABORATORY, TYPE, values, "if_equ", "bf_template"));
    }

    /**
     * 新增实验室参数并关联实验室参数组容器
     *
     * @param data
     * @return 实验室参数
     * @throws BusinessException
     */
    @Override
    @Transactional
    public ResultInfo<?> addLaboratoryParams(JSONObject data) throws BusinessException {
        String type = data.getString("type");
        String className = data.getString("className");
        String name = data.getString("name");
        JSONObject values = data.getJSONObject("values");

        String containerId = data.getString("containerId");
        ValidateUtil.hasEmpty(containerId, type, className, name, values);
        // 添加资源实例
        JSONObject addJson = resourceInstanceDslServiceImpl.add(type, className, name, values);
        if (addJson != null && StringUtils.isNotEmpty(addJson.getString("id"))) {
            String linkId = addJson.getString("id");
            JSONObject hierInsJson = JsonUtil.buildJson(new Object[]{"containerModel", this.laboratoryModel, "containerClassName", this.laboratoryClassName, "containerId", containerId, "parentId", this.laboratoryParentId, "linkId", linkId, "linkType", laboratoryLinkType, "linkClassName", laboratoryLinkClassName, "values", JsonUtil.get(addJson, "values")});
            hierInstanceDslServiceImpl.addChild(hierInsJson);
        }
        return JsonResult.success(addJson);
    }

    /**
     * 品规下是否有工艺参数或实验室参数实体
     *
     * @param data
     * @return 是或否
     * @throws BusinessException
     */
    @Override
    @Transactional
    public ResultInfo<?> isProductHasContent(JSONObject data) throws BusinessException {
        int id = data.getIntValue("id");
        if (null == data.get("id")) {
            return JsonResult.error(500, "id不能为空");
        }
        String speCond = "className=='" + CLASS_NAME_SPECIFICATION + "'&&type=='" + TYPE + "'&&if_equ==" + id + "&&bf_template==true";
        List<LogicInstance> specList = logicInstanceDslServiceImpl.fetchInstanceList(speCond, CLASS_NAME_SPECIFICATION, null);
        List<HierInstance> specHier = new ArrayList<>();    //品规下的工艺参数
        if (specList.size() > 0) {
            LogicInstance l1 = specList.get(0);
            specHier = this.hierInstanceDslServiceImpl.queryByContainerId(ModelType.Logic.getCode(), l1.getClassName(), l1.getId());
        }
        String labCond = "className=='" + CLASS_NAME_LABORATORY + "'&&type=='" + TYPE + "'&&if_equ==" + id + "&&bf_template==true";
        List<LogicInstance> labList = logicInstanceDslServiceImpl.fetchInstanceList(labCond, CLASS_NAME_LABORATORY, null);
        List<HierInstance> labHier = new ArrayList<>(); //品规下的实验室参数
        if (labHier.size() > 0) {
            LogicInstance l2 = labList.get(0);
            labHier = this.hierInstanceDslServiceImpl.queryByContainerId(ModelType.Logic.getCode(), l2.getClassName(), l2.getId());
        }
        if (specHier.size() > 2 || labHier.size() > 2) {
            return JsonResult.success(false);
        }
        return JsonResult.success(true);
    }
}